package com.mugui.base.client.net.bagsend;

import com.mugui.base.base.Component;
import com.mugui.base.base.InitMethod;
import com.mugui.base.client.net.auto.AutoTask;
import com.mugui.base.client.net.base.Task;
import com.mugui.base.client.net.base.TaskInterface;
import com.mugui.base.client.net.task.TaskManager;
import lombok.Getter;
import lombok.Setter;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@Task(value = Task.DEFAULT, time = 0)
@AutoTask
public class BagSendTask implements TaskInterface {

    private ThreadPoolExecutor executor;
    private final PriorityBlockingQueue<PriorityTask> priorityQueue = new PriorityBlockingQueue<>();
    private volatile boolean running = false;

    @Getter
    @Setter
    private int corePoolSize = 32;

    @Getter
    @Setter
    private int maxPoolSize = 1024;

    public void init() {
        // 从系统属性读取配置
        corePoolSize = Integer.parseInt(
                System.getProperty("bag_send_task_core_pool_size", String.valueOf(corePoolSize)));
        maxPoolSize = Integer.parseInt(
                System.getProperty("bag_send_task_maximum_pool_size", String.valueOf(maxPoolSize)));

        // 初始化线程池
        executor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                3000L, TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                new PriorityThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );

        executor.prestartAllCoreThreads();
    }

    @Override
    public void run() {
        running = true;
        Thread.currentThread().setUncaughtExceptionHandler((t, e) -> {
            e.printStackTrace();
            restartTask();
        });

        while (running) {
            try {
                PriorityTask task = priorityQueue.take();
                executor.execute(task);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void shutdown() {
        running = false;
        executor.shutdownNow();
        try {
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                System.err.println("线程池关闭超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    public void addTask(Runnable task, Integer priority) {
        priorityQueue.put(new PriorityTask(task, priority));
    }

    private void restartTask() {
        shutdown();
        TaskManager.getTaskManager().add(new BagSendTask());
    }

    private static class PriorityTask implements Runnable, Comparable<PriorityTask> {
        private final Runnable task;
        private final int priority;

        PriorityTask(Runnable task, Integer priority) {
            this.task = task;
            if (priority == null) {
                priority = 0;
            }
            this.priority = priority;
        }

        @Override
        public void run() {
            task.run();
        }

        @Override
        public int compareTo(PriorityTask other) {
            return Integer.compare(this.priority, other.priority);
        }
    }

    private static class PriorityThreadFactory implements ThreadFactory {
        private final AtomicInteger threadNumber = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "bag-send-pool-" + threadNumber.getAndIncrement());
            t.setPriority(Thread.NORM_PRIORITY);
            t.setDaemon(false);
            return t;
        }
    }
}
